package com.cloud.lan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloud.lan.api.dto.req.LanActivityReq;
import com.cloud.lan.api.dto.resp.LanActivityRecordResp;
import com.cloud.lan.api.dto.resp.LanActivityResp;
import com.cloud.lan.api.dto.resp.LanUserResp;
import com.cloud.lan.config.cache.LoadingCacheConfiguration;
import com.cloud.lan.dao.LanActivityCodeMapper;
import com.cloud.lan.dao.LanActivityMapper;
import com.cloud.lan.dao.LanActivityMiddleMapper;
import com.cloud.lan.dao.LanActivityRecordMapper;
import com.cloud.lan.entity.base.BaseResponse;
import com.cloud.lan.entity.base.exceptions.BaseException;
import com.cloud.lan.entity.enums.ActivityAcTypeEnum;
import com.cloud.lan.entity.enums.ActivityStatusEnum;
import com.cloud.lan.entity.enums.LanError;
import com.cloud.lan.entity.enums.LanMessage;
import com.cloud.lan.entity.model.dataobject.LanActivityCodeDO;
import com.cloud.lan.entity.model.dataobject.LanActivityDO;
import com.cloud.lan.entity.model.dataobject.LanActivityMiddleDO;
import com.cloud.lan.entity.model.dataobject.LanActivityRecordDO;
import com.cloud.lan.service.ILanActivityService;
import com.cloud.lan.service.tx.lbs.TxMapPointService;

import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;

import static com.cloud.lan.entity.enums.ActivityAcTypeEnum.AC_TYPE_外部系统券;
import static com.cloud.lan.entity.enums.ActivityAcTypeEnum.AC_TYPE_线下劵;
import static com.cloud.lan.entity.utils.ConstantInterface.Enum.ConstantNumber.ONE;
import static com.cloud.lan.entity.utils.ConstantInterface.Enum.ConstantNumber.ZERO;

/**
 * <p>
 * 兑换码活动信息表 服务实现类
 * </p>
 *
 * @author xyqierkang@163.com
 * @since 2021-12-23
 */
@Slf4j
@Service
public class LanActivityServiceImpl extends ServiceImpl<LanActivityMapper, LanActivityDO> implements ILanActivityService {

    @Resource
    LoadingCacheConfiguration cacheConfiguration;
    @Resource
    private LanActivityMapper lanActivityMapper;
    @Resource
    private LanActivityRecordMapper lanActivityRecordMapper;
    @Resource
    private LanActivityMiddleMapper lanActivityMiddleMapper;
    @Resource
    private TxMapPointService txMapPointService;
    @Resource
    private LanActivityCodeMapper lanActivityCodeMapper;

    private boolean checkInLogin(String token) {
        LanUserResp lanUserResp = cacheConfiguration.userInfo.getUnchecked(token);
        return CharSequenceUtil.isNotEmpty(lanUserResp.getUserPhone());
    }

    public static void main(String[] args) {
        String aa = "[\"上海市\",\"南京市\",\"香港特别行政区\",\"海南省\",\"海口市\"]";
        System.out.println(CharSequenceUtil.containsAny(aa, "海南省", "三亚市"));
    }

    @Override
    public BaseResponse<Object> getActivityList(String token, String lng, String lat) {
        log.info("#查询 可用兑换券列表 token {} lng {} lat {}", token, lng, lat);
        LambdaQueryWrapper<LanActivityDO> laQw = new LambdaQueryWrapper<>();
        List<Integer> types = new ArrayList<>();
        laQw.eq(LanActivityDO::getStatus, ONE.getKey()).orderByDesc(LanActivityDO::getCreateTime);
        types.add(AC_TYPE_线下劵.getId());
        // 校验用户是否注册
//        if (checkInLogin(token)) {
//            types.add(FIVE.getKey());
//        }
        // 前端会进行判断用户是否登录
        types.add(AC_TYPE_外部系统券.getId());
        laQw.in(LanActivityDO::getAcType, types);
        List<LanActivityDO> listMap = lanActivityMapper.selectList(laQw);
        List<LanActivityDO> list = new ArrayList<>();
        // 如果经纬度不空，校验用户经纬度城市是否在这个范围
        if (CharSequenceUtil.isAllNotBlank(lng, lat)) {
            Map<String, Object> mapPoint = txMapPointService.getLocation(lng, lat);
            String province = String.valueOf(mapPoint.get("province"));
            String city = String.valueOf(mapPoint.get("city"));
//            ArrayList<String> mapsList = Lists.newArrayList(province, city);
            list = listMap.stream().filter(f -> {
                if (CharSequenceUtil.isNotEmpty(f.getCityName())) {
                    return CharSequenceUtil.containsAny(f.getCityName(), province, city);
                }
                return false;
            }).collect(Collectors.toList());
        }
        // 如果经纬度空，查询type=5 CityName空的城市返回
        if (CharSequenceUtil.isAllBlank(lng, lat)) {
            list = listMap.stream().filter(f -> CharSequenceUtil.isEmpty(f.getCityName())).collect(Collectors.toList());
        }
        list.addAll(listMap.stream().
                filter(f -> f.getAcType() != 5).collect(Collectors.toList()));
        List<LanActivityResp> listResp = new ArrayList<>();
        LanUserResp lanUserResp = cacheConfiguration.userInfo.getUnchecked(token);
        List<Long> activityIdList = lanActivityMiddleMapper.selectList(new LambdaQueryWrapper<LanActivityMiddleDO>()
                        .eq(LanActivityMiddleDO::getUserId, lanUserResp.getUserId())).stream()
                .map(LanActivityMiddleDO::getActivityId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(activityIdList)) {
            List<LanActivityDO> resultIdList = lanActivityMapper.selectList(new LambdaQueryWrapper<LanActivityDO>()
                    .in(LanActivityDO::getId,
                            activityIdList));
            list.addAll(resultIdList);
        }
        list.forEach(l -> {
            // 判断用户是否领取了
            LambdaQueryWrapper<LanActivityRecordDO> larQw = new LambdaQueryWrapper<>();
            larQw.eq(LanActivityRecordDO::getUserId, lanUserResp.getUserId())
                    .eq(LanActivityRecordDO::getActivityId, l.getId());
            LanActivityResp resp = new LanActivityResp();
            // 组装数组
            BeanUtil.copyProperties(l, resp);
            resp.setIsActivity(lanActivityRecordMapper.selectCount(larQw) > 0);
            listResp.add(resp);
        });
        List<LanActivityResp> newListResp = new ArrayList<>();
        listResp.forEach(obj -> {
            if (!newListResp.contains(obj)) {
                newListResp.add(obj);
            }
        });
        return BaseResponse.success(newListResp);
    }

    @Override
    public BaseResponse<Object> getActivityUsers(String token, Integer status) {
        log.info("#查询 用户兑换券列表 token：{} status {}", token, status);
        LanUserResp lanUserResp = cacheConfiguration.userInfo.getUnchecked(token);
        LambdaQueryWrapper<LanActivityRecordDO> larQw = new LambdaQueryWrapper<>();
        larQw.eq(LanActivityRecordDO::getUserId, lanUserResp.getUserId());
        larQw.orderByDesc(LanActivityRecordDO::getCreateTime);
        List<LanActivityRecordDO> list = lanActivityRecordMapper.selectList(larQw);
        List<LanActivityRecordResp> listResp = new ArrayList<>();
        list.forEach(l -> {
            LanActivityDO lanActivityDO = lanActivityMapper.selectById(l.getActivityId());
            LanActivityRecordResp resp = new LanActivityRecordResp();
            // 组装数据
            BeanUtil.copyProperties(lanActivityDO, resp);
            BeanUtil.copyProperties(l, resp);
            // 查询劵是否失效了
            if (DateUtil.compare(lanActivityDO.getEndTime(), DateUtil.date()) < ZERO.getKey()) {
                resp.setStatus(ActivityStatusEnum.STATUS_2_已失效.getId());
            }
            if (!lanActivityDO.getStatus().equals(ActivityStatusEnum.STATUS_1_已使用.getId())) {
                resp.setStatus(ActivityStatusEnum.STATUS_2_已失效.getId());
            }
            if (status.equals(resp.getStatus())) {
                listResp.add(resp);
            }
        });
        return BaseResponse.success(listResp);
    }

    @Override
    public BaseResponse<Object> userReceive(String token, LanActivityReq req) {
        log.info("#用户领取兑换券 token：{} activity：{}", token, req);
        LambdaQueryWrapper<LanActivityDO> laQw = new LambdaQueryWrapper<>();
        laQw
                .eq(LanActivityDO::getStatus, ONE.getKey())
                .eq(LanActivityDO::getId, req.getActivityId());
        LanActivityDO lanActivityDO = lanActivityMapper.selectOne(laQw);
        if (ObjectUtil.isEmpty(lanActivityDO)) {
            log.error("userReceive 兑换券已下架 token {} activityId {}", token, req.getActivityId());
            throw new BaseException(LanError.LAN_020004);
        }
        //领取优惠劵验证逻辑不同，区分 线下劵、外部系统卷
        userReceiveVerification(lanActivityDO);
        LambdaQueryWrapper<LanActivityRecordDO> larQw = new LambdaQueryWrapper<>();
        LanUserResp lanUserResp = cacheConfiguration.userInfo.getUnchecked(token);
        larQw.eq(LanActivityRecordDO::getUserId, lanUserResp.getUserId())
                .eq(LanActivityRecordDO::getActivityId, req.getActivityId());
        if (lanActivityRecordMapper.selectCount(larQw) > ZERO.getKey()) {
            log.error("userReceive 你已经领取过，无法再次领取 token {} activityId {}", token, req.getActivityId());
            throw new BaseException(LanError.LAN_020002);
        }
        // 如果是系统
        LanActivityRecordDO activityRecordDO = new LanActivityRecordDO();
        if (lanActivityDO.getAcType().equals(AC_TYPE_外部系统券.getId())) {
            LambdaQueryWrapper<LanActivityCodeDO> codeQw = new LambdaQueryWrapper<>();
            codeQw.eq(LanActivityCodeDO::getCodeStatus, ZERO.getKey());
            codeQw.eq(LanActivityCodeDO::getActivityId, req.getActivityId());
            codeQw.last("limit 1");
            LanActivityCodeDO lanActivityCodeDO = lanActivityCodeMapper.selectOne(codeQw);
            if (ObjectUtil.isNotEmpty(lanActivityCodeDO)) {
                activityRecordDO.setCode(lanActivityCodeDO.getCode());
                lanActivityCodeDO.setCodeStatus(ONE.getKey());
                lanActivityCodeMapper.updateById(lanActivityCodeDO);
            }
            lanActivityDO.setAcCount(lanActivityDO.getAcCount() > 0 ?
                    lanActivityDO.getAcCount() - 1 : lanActivityDO.getAcCount());
            lanActivityMapper.updateById(lanActivityDO);
        }
        activityRecordDO.setUserId(lanUserResp.getUserId());
        activityRecordDO.setActivityId(req.getActivityId());
        activityRecordDO.setAcName(lanActivityDO.getAcName());
        activityRecordDO.setRecordDesc("用户主动领取");
        activityRecordDO.setCreateTime(DateUtil.date());
        lanActivityRecordMapper.insert(activityRecordDO);
        return BaseResponse.success();
    }

    @Override
    public BaseResponse<Object> userApply(String token, LanActivityReq req) {
        log.info("#用户使用-核销兑换券 token：{} activity：{}", token, req);
        LambdaQueryWrapper<LanActivityRecordDO> larQw = new LambdaQueryWrapper<>();
        LanUserResp lanUserResp = cacheConfiguration.userInfo.getUnchecked(token);
        larQw.eq(LanActivityRecordDO::getUserId, lanUserResp.getUserId())
                .eq(LanActivityRecordDO::getActivityId, req.getActivityId())
                .eq(LanActivityRecordDO::getStatus, ZERO.getKey());
        LanActivityRecordDO activityRecordDO = lanActivityRecordMapper.selectOne(larQw);
        LambdaQueryWrapper<LanActivityDO> laQw = new LambdaQueryWrapper<>();
        laQw
//                .eq(LanActivityDO::getAcType, ONE.getKey())
                .eq(LanActivityDO::getStatus, ONE.getKey())
                .eq(LanActivityDO::getId, req.getActivityId());
        LanActivityDO lanActivityDO = lanActivityMapper.selectOne(laQw);
        if (ObjectUtil.isEmpty(activityRecordDO)) {
            log.error("userApply 兑换券查询空 token {} activityId {}", token, req.getActivityId());
            throw new BaseException(LanError.LAN_020001);
        }
        if (ObjectUtil.isEmpty(lanActivityDO)) {
            log.error("userApply 兑换券查询空 token {} activityId {}", token, req.getActivityId());
            throw new BaseException(LanError.LAN_020001);
        }
        if (DateUtil.compare(lanActivityDO.getStartTime(), DateUtil.date()) > ZERO.getKey()) {
            log.error("userApply {} token {} activityId {}", LanError.LAN_020010.getMsg(), token, req.getActivityId());
            throw new BaseException(LanError.LAN_020010);
        }
        if (!lanActivityDO.getAcCode().equals(req.getAcCode())) {
            log.error("userApply 口令错误 token {} activityId {}", token, req.getActivityId());
            throw new BaseException(LanError.LAN_020005);
        }
        activityRecordDO.setRecordTime(DateUtil.date());
        activityRecordDO.setRecordDesc("用户主动核销");
        activityRecordDO.setStatus(ONE.getKey());
        lanActivityRecordMapper.updateById(activityRecordDO);
        return BaseResponse.success(LanMessage.LAN_100000.getMsg());
    }

    /**
     * 领取优惠劵验证逻辑不同，区分 线下劵、外部系统卷
     * @author qierkang@leoao.com
     * @return void
     * 2022/12/25 20:13
     */
    private void userReceiveVerification(LanActivityDO lanActivityDO) {
        ActivityAcTypeEnum activityAcTypeEnum = ActivityAcTypeEnum.getEnumByCode(lanActivityDO.getAcType());
        switch (activityAcTypeEnum) {
            case AC_TYPE_线下劵:
                // 查询已领取总数
                LambdaQueryWrapper<LanActivityRecordDO> larCkQw = new LambdaQueryWrapper<>();
                larCkQw.eq(LanActivityRecordDO::getActivityId, lanActivityDO.getId());
                Integer receiveCount = lanActivityRecordMapper.selectCount(larCkQw);
                // 用户领取，实时校验库存
                if (lanActivityDO.getAcCount() <= receiveCount) {
                    log.error("userReceive>userReceiveVerification 当前库存不足，无法购买 activityId {} {}", lanActivityDO.getId(), AC_TYPE_线下劵);
                    throw new BaseException(LanError.LAN_020003);
                }
                break;

            case AC_TYPE_外部系统券:
                LambdaQueryWrapper<LanActivityCodeDO> codeQw = new LambdaQueryWrapper<>();
                codeQw.eq(LanActivityCodeDO::getCodeStatus, ZERO.getKey());
                codeQw.eq(LanActivityCodeDO::getActivityId, lanActivityDO.getId());
                if (lanActivityCodeMapper.selectCount(codeQw) == 0) {
                    log.error("userReceive>userReceiveVerification 当前库存不足，无法购买 activityId {} {}", lanActivityDO.getId(), AC_TYPE_外部系统券);
                    throw new BaseException(LanError.LAN_020003);
                }
                break;
            default:
                break;
        }
    }
}
